/*
 * restserver - A smart, efficient, low consumption RESTful application service platform writen in C
 * author	: calvin
 * email	: calvinwilliams@163.com
 *
 * Licensed under the Apache License v2.0, see the file LICENSE in base directory.
 */

#include "in.h"

int ParseHttpToRestServerContext( struct RestServerContext *ctx )
{
	/*
	
	/path1/path2/file
	 p1   p2
	
	/path1/path2/file?key1=value1&key2=value2
	             p1  p2
	
	                       p3    p4
	/path1/path2/file?key1=value1&key2=value2
	                  p1  p2
	
	/path1/path2/file?key1&key2=value2
	                  p1  p2
	
	*/
	struct HttpRequest	*p_http_req = NULL ;
	
	char			*p1 = NULL ;
	char			*p2 = NULL ;
	char			*p3 = NULL ;
	char			*p4 = NULL ;
	char			*pe = NULL ;
	
	p_http_req = & (ctx->http_req) ;
	memset( p_http_req , 0x00 , sizeof(struct HttpRequest) );
	
	p_http_req->http_method = GetHttpHeaderPtr_METHOD( ctx->p_accepted_session->http_env , & (p_http_req->http_method_len) ) ;
	DEBUGLOG( "http_method[%.*s]" , p_http_req->http_uri_len,p_http_req->http_method )
	
	p_http_req->http_uri = GetHttpHeaderPtr_URI( ctx->p_accepted_session->http_env , & (p_http_req->http_uri_len) ) ;
	DEBUGLOG( "http_uri[%.*s]" , p_http_req->http_uri_len,p_http_req->http_uri )
	
	if( p_http_req->http_uri[0] != '/' )
		return RESTSERVER_ERROR_URI_FIRST_CHARACTER;
	
	p2 = p1 = p_http_req->http_uri + 1 ;
	pe = p_http_req->http_uri + p_http_req->http_uri_len - 1 ;
	p_http_req->http_uri_paths_count = 0 ;
	while(1)
	{
		if( p2 > pe )
		{
			if( p_http_req->http_uri_paths_count >= sizeof(p_http_req->http_uri_paths)/sizeof(p_http_req->http_uri_paths[0]) )
				return RESTSERVER_ERROR_TOO_MANY_HTTP_URI_PATHS;
			if( p2 == p1 )
			{
				p_http_req->http_uri_paths[p_http_req->http_uri_paths_count].path = "" ;
				p_http_req->http_uri_paths[p_http_req->http_uri_paths_count].path_len = 0 ;
				DEBUGLOG( "p2>pe&&p2==p1 : parse out http_path[%d][%.*s]" , p_http_req->http_uri_paths_count , p_http_req->http_uri_paths[p_http_req->http_uri_paths_count].path_len,p_http_req->http_uri_paths[p_http_req->http_uri_paths_count].path )
				p_http_req->http_uri_paths_count++;
			}
			else
			{
				p_http_req->http_uri_paths[p_http_req->http_uri_paths_count].path = p1 ;
				p_http_req->http_uri_paths[p_http_req->http_uri_paths_count].path_len = p2 - p1 ;
				DEBUGLOG( "p2>pe&&p2>p1 : parse out http_path[%d][%.*s]" , p_http_req->http_uri_paths_count , p_http_req->http_uri_paths[p_http_req->http_uri_paths_count].path_len,p_http_req->http_uri_paths[p_http_req->http_uri_paths_count].path )
				p_http_req->http_uri_paths_count++;
			}
			
			break;
		}
		else if( (*p2) == '/' )
		{
			if( p_http_req->http_uri_paths_count >= sizeof(p_http_req->http_uri_paths)/sizeof(p_http_req->http_uri_paths[0]) )
				return RESTSERVER_ERROR_TOO_MANY_HTTP_URI_PATHS;
			p_http_req->http_uri_paths[p_http_req->http_uri_paths_count].path = p1 ;
			p_http_req->http_uri_paths[p_http_req->http_uri_paths_count].path_len = p2 - p1 ;
			DEBUGLOG( "p2=='/' : parse out http_path[%d][%.*s]" , p_http_req->http_uri_paths_count , p_http_req->http_uri_paths[p_http_req->http_uri_paths_count].path_len,p_http_req->http_uri_paths[p_http_req->http_uri_paths_count].path )
			p_http_req->http_uri_paths_count++;
			
			p2 = p1 = p2 + 1 ;
		}
		else if( (*p2) == '?' )
		{
			if( p_http_req->http_uri_paths_count >= sizeof(p_http_req->http_uri_paths)/sizeof(p_http_req->http_uri_paths[0]) )
				return RESTSERVER_ERROR_TOO_MANY_HTTP_URI_PATHS;
			if( p2 == p1 )
			{
				p_http_req->http_uri_paths[p_http_req->http_uri_paths_count].path = "" ;
				p_http_req->http_uri_paths[p_http_req->http_uri_paths_count].path_len = 0 ;
				DEBUGLOG( "p2=='?'&&p2==p1 : parse out http_path[%d][%.*s]" , p_http_req->http_uri_paths_count , p_http_req->http_uri_paths[p_http_req->http_uri_paths_count].path_len,p_http_req->http_uri_paths[p_http_req->http_uri_paths_count].path )
				p_http_req->http_uri_paths_count++;
			}
			else
			{
				p_http_req->http_uri_paths[p_http_req->http_uri_paths_count].path = p1 ;
				p_http_req->http_uri_paths[p_http_req->http_uri_paths_count].path_len = p2 - p1 ;
				DEBUGLOG( "p2=='?'&&p2>p1 : parse out http_path[%d][%.*s]" , p_http_req->http_uri_paths_count , p_http_req->http_uri_paths[p_http_req->http_uri_paths_count].path_len,p_http_req->http_uri_paths[p_http_req->http_uri_paths_count].path )
				p_http_req->http_uri_paths_count++;
			}
			
			p2 = p1 = p2 + 1 ;
			break;
		}
		else
		{
			p2++;
		}
	}
	
	if( p2 <= pe )
	{
		while(1)
		{
			if( p2 > pe )
			{
				if( p2 > p1 )
				{
					if( p_http_req->http_uri_queries_count >= sizeof(p_http_req->http_uri_queries)/sizeof(p_http_req->http_uri_queries[0]) )
						return RESTSERVER_ERROR_TOO_MANY_HTTP_URI_PATHS;
					p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].key = p1 ;
					p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].key_len = p2 - p1 ;
					p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].value = "" ;
					p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].value_len = 0 ;
					DEBUGLOG( "p2=='&' : parse out http_query[%d][%.*s][%.*s]" , p_http_req->http_uri_queries_count , p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].key_len,p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].key , p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].value_len,p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].value );
					p_http_req->http_uri_queries_count++;
				}
				
				break;
			}
			else if( (*p2) == '&' )
			{
				if( p_http_req->http_uri_queries_count >= sizeof(p_http_req->http_uri_queries)/sizeof(p_http_req->http_uri_queries[0]) )
					return RESTSERVER_ERROR_TOO_MANY_HTTP_URI_PATHS;
				p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].key = p1 ;
				p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].key_len = p2 - p1 ;
				p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].value = "" ;
				p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].value_len = 0 ;
				DEBUGLOG( "p2=='&' : parse out http_query[%d][%.*s][%.*s]" , p_http_req->http_uri_queries_count , p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].key_len,p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].key , p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].value_len,p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].value );
				p_http_req->http_uri_queries_count++;
				
				p2 = p1 = p2 + 1 ;
			}
			else if( (*p2) == '=' )
			{
				p4 = p3 = p2 + 1 ;
				while(1)
				{
					if( p4 > pe )
					{
						if( p_http_req->http_uri_queries_count >= sizeof(p_http_req->http_uri_queries)/sizeof(p_http_req->http_uri_queries[0]) )
							return RESTSERVER_ERROR_TOO_MANY_HTTP_URI_PATHS;
						if( p4 > p3 )
						{
							p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].key = p1 ;
							p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].key_len = p2 - p1 ;
							p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].value = p3 ;
							p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].value_len = p4 - p3 ;
							DEBUGLOG( "p2=='='&&p4>pe&&p4>p3 : parse out http_query[%d][%.*s][%.*s]" , p_http_req->http_uri_queries_count , p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].key_len,p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].key , p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].value_len,p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].value );
							p_http_req->http_uri_queries_count++;
						}
						else
						{
							p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].key = p1 ;
							p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].key_len = p2 - p1 ;
							p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].value = "" ;
							p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].value_len = 0 ;
							DEBUGLOG( "p2=='='&&p4>pe&&p4==p3 : parse out http_query[%d][%.*s][%.*s]" , p_http_req->http_uri_queries_count , p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].key_len,p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].key , p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].value_len,p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].value );
							p_http_req->http_uri_queries_count++;
						}
						
						break;
					}
					else if( (*p4) == '&' )
					{
						if( p_http_req->http_uri_queries_count >= sizeof(p_http_req->http_uri_queries)/sizeof(p_http_req->http_uri_queries[0]) )
							return RESTSERVER_ERROR_TOO_MANY_HTTP_URI_PATHS;
						p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].key = p1 ;
						p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].key_len = p2 - p1 ;
						p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].value = p3 ;
						p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].value_len = p4 - p3 ;
						DEBUGLOG( "p2=='='&&p4=='&' : parse out http_query[%d][%.*s][%.*s]" , p_http_req->http_uri_queries_count , p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].key_len,p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].key , p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].value_len,p_http_req->http_uri_queries[p_http_req->http_uri_queries_count].value );
						p_http_req->http_uri_queries_count++;
						
						p2 = p1 = p4 + 1 ;
						break;
					}
					p4++;
				}
				if( p4 > pe )
					break;
			}
			else
			{
				p2++;
			}
		}
	}
	
	p_http_req->http_host = QueryHttpHeaderPtr( ctx->p_accepted_session->http_env , "Host" , & (p_http_req->http_host_len) );
	if( STRNCMPSTR( p_http_req->http_host , p_http_req->http_host_len , != , ctx->conf.http.domain ) )
	{
		ERRORLOG( "diff http domain[%.*s] config domain[%s]" , p_http_req->http_host_len,p_http_req->http_host , ctx->conf.http.domain )
		return RESTSERVER_ERROR_HTTP_DOMAIN;
	}
	else
	{
		DEBUGLOG( "diff http domain[%.*s] config domain[%s]" , p_http_req->http_host_len,p_http_req->http_host , ctx->conf.http.domain )
	}
	
	p_http_req->http_body = GetHttpBodyPtr( ctx->p_accepted_session->http_env , & (p_http_req->http_body_len) ) ;
	
	return 0;
}

char *GetRestServerContextHttpMethod( struct RestServerContext *ctx , int *p_method_len )
{
	if( p_method_len )
		(*p_method_len) = ctx->http_req.http_method_len ;
	return ctx->http_req.http_method;
}

char *GetRestServerContextHttpUri( struct RestServerContext *ctx , int *p_uri_len )
{
	if( p_uri_len )
		(*p_uri_len) = ctx->http_req.http_uri_len ;
	return ctx->http_req.http_uri;
}

int GetRestServerContextHttpUriPathsCount( struct RestServerContext *ctx )
{
	return ctx->http_req.http_uri_paths_count;
}

char *GetRestServerContextHttpUriPathPtr( struct RestServerContext *ctx , int index , int *p_path_len )
{
	if( index < 1 || index > ctx->http_req.http_uri_paths_count )
		return NULL;
	
	if( p_path_len )
		(*p_path_len) = ctx->http_req.http_uri_paths[index-1].path_len ;
	return ctx->http_req.http_uri_paths[index-1].path;
}

int GetRestServerContextHttpUriQueriesCount( struct RestServerContext *ctx )
{
	return ctx->http_req.http_uri_queries_count;
}

char *GetRestServerContextHttpUriQueryKeyPtr( struct RestServerContext *ctx , int index , int *p_key_len )
{
	if( index < 1 || index > ctx->http_req.http_uri_queries_count )
		return NULL;
	
	if( p_key_len )
		(*p_key_len) = ctx->http_req.http_uri_queries[index-1].key_len ;
	return ctx->http_req.http_uri_queries[index-1].key;
}

char *GetRestServerContextHttpUriQueryValuePtr( struct RestServerContext *ctx , int index , int *p_value_len )
{
	if( index < 1 || index > ctx->http_req.http_uri_queries_count )
		return NULL;
	
	if( p_value_len )
		(*p_value_len) = ctx->http_req.http_uri_queries[index-1].value_len ;
	return ctx->http_req.http_uri_queries[index-1].value;
}

char *GetRestServerContextHttpRequestBodyPtr( struct RestServerContext *ctx , int *p_body_len )
{
	if( p_body_len )
		(*p_body_len) = ctx->http_req.http_body_len ;
	return ctx->http_req.http_body;
}

void SetRestServerContextUserData( struct RestServerContext *ctx , void *user_data )
{
	ctx->user_data = user_data ;
	return;
}

void *GetRestServerContextUserData( struct RestServerContext *ctx )
{
	return ctx->user_data;
}

int FormatResetServerContextHttpResponse( struct RestServerContext *ctx , char *http_response_body , int http_response_body_len , char *http_header_format , va_list valist )
{
	struct HttpBuffer	*b = NULL ;
	
	int			nret = 0 ;
	
	nret = FormatHttpResponseStartLine( HTTP_OK , ctx->p_accepted_session->http_env , 0 , NULL ) ;
	if( nret )
		return ASSEMBLE2_ERROR_CODE(RESTSERVER_MODULE_NO_FASTERHTTP,nret);
	
	b = GetHttpResponseBuffer(ctx->p_accepted_session->http_env) ;
	
	if( http_header_format )
	{
		nret = StrcatvHttpBuffer( b , http_header_format , valist ) ;
		if( nret )
			return ASSEMBLE2_ERROR_CODE(RESTSERVER_MODULE_NO_FASTERHTTP,nret);
	}
	
	if( http_response_body == NULL )
	{
		nret = StrcatHttpBuffer( b , HTTP_RETURN_NEWLINE ) ;
		if( nret )
			return ASSEMBLE2_ERROR_CODE(RESTSERVER_MODULE_NO_FASTERHTTP,nret);
	}
	else
	{
		nret = StrcatfHttpBuffer( b , "Content-length: %d" HTTP_RETURN_NEWLINE HTTP_RETURN_NEWLINE , http_response_body_len ) ;
		if( nret )
			return ASSEMBLE2_ERROR_CODE(RESTSERVER_MODULE_NO_FASTERHTTP,nret);
		
		nret = MemcatHttpBuffer( b , http_response_body , http_response_body_len ) ;
		if( nret )
			return ASSEMBLE2_ERROR_CODE(RESTSERVER_MODULE_NO_FASTERHTTP,nret);
	}
	
	return 0;
}

